﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Messages;
using ZeroMQ;

namespace Zmq
{
    class Program
    {
        private static string _server;
        static void Main(string[] args)
        {
            _server = string.Format("tcp://{0}", args[0]);
            System.Threading.Tasks.Task.Factory.StartNew(Client, null, TaskCreationOptions.LongRunning);
            Console.ReadLine();
        }


        public static void Client(object state)
        {
            using (var ctx = ZmqContext.Create())
            {
                while (true)
                {
                    var socket = CreateSocket(ctx);

                    try
                    {
                        while (true)
                        {
                            var lpi = GetLpi();
                            var msg = GetMessage(lpi);
                            socket.Send(msg);
                            Console.WriteLine("send " + lpi.Id + ", wait for reply");
                            var reply = GetReply(ctx, socket, msg);
                            if (string.IsNullOrEmpty(reply) || string.CompareOrdinal(lpi.Id, reply) != 0)
                            {
                                Console.WriteLine("server malfunction or died, reconnect");
                                break;
                            }
                            else
                            {
                                Console.WriteLine("\tget reply " + reply);
                            }
                            Thread.Sleep(50);
                        }
                    }
                    catch (ZeroMQ.ZmqSocketException ex)
                    {
                        Console.WriteLine(ex.Message);
                    }



                }
            }
        }

        private static byte[] GetMessage(Lpi lpi)
        {
            using (var stream = new MemoryStream())
            {
                ProtoBuf.Serializer.Serialize(stream, lpi);
                return stream.ToArray();
            }
        }

        private static Lpi GetLpi()
        {
            var dt = DateTime.Now;
            var p = new Messages.Lpi
                        {
                            Age = dt.Millisecond,
                            CaptureTime = dt,
                            Id = Guid.NewGuid().ToString(),
                            Image = new byte[dt.Millisecond]
                        };
            return p;
        }

        private static ZmqSocket CreateSocket(ZmqContext ctx)
        {
            var socket = ctx.CreateSocket(SocketType.REQ);
            socket.ReceiveReady += SocketOnReceiveReady;
            socket.Connect(_server);
            return socket;
        }

        private static void SocketOnReceiveReady(object sender, SocketEventArgs socketEventArgs)
        {

        }

        private static string GetReply(ZmqContext ctx, ZmqSocket socket, byte[] messageToResend)
        {
            var retries = 3;
            while (true)
            {

                var poller = new Poller();
                poller.AddSocket(socket);

                var count = poller.Poll(TimeSpan.FromSeconds(2.5));
                if (count == 0)
                {
                    --retries;
                    if (retries == 0)
                    {
                        return null;
                    }
                    else
                    {
                        socket = CreateSocket(ctx);
                        socket.Send(messageToResend);
                    }
                }
                else
                {
                    return socket.Receive(Encoding.Unicode);
                }
            }
        }
    }
}
